﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Moq;
using MongoServices.Tests.TestHelpers;
using MongoServices.Tests.Stubs;
using MongoDB.Bson;

namespace MongoServices.Tests.ReadWriteServiceTests
{
	public class ReadWriteServiceTests : TestBase
	{
		protected Mock<IReadWriteRepository<TestModelSimple>> ReadWriteRepositoryMock { get; private set; }
		protected ReadWriteService<TestModelSimple> ReadWriteServiceTestModelSimple { get; private set; }

		public ReadWriteServiceTests()
		{
			Setup();
		}

		private void Setup()
		{
			ReadWriteRepositoryMock = new Mock<IReadWriteRepository<TestModelSimple>>();
			ReadWriteServiceTestModelSimple = new ReadWriteServiceTestModelSimpleStub(ReadWriteRepositoryMock.Object);
		}
	}

	public class WhenSaveWithModelIsCalled : ReadWriteServiceTests
	{
		[Fact]
		public void RepositorySaveMethodIsCalledOnceWithTheSameModel()
		{
			var testModel = new TestModelSimple() { TestField = "TestData" };

			ReadWriteServiceTestModelSimple.Save(testModel);

			ReadWriteRepositoryMock.Verify(m => m.Save(It.Is<TestModelSimple>(model => model == testModel)), Times.Once(), "The repository save method was not called or was called with the wrong model.");
		}

		[Fact]
		public void TheResponseFromTheMethodIsSaveResultSaved()
		{
			var testModel = new TestModelSimple() { TestField = "TestData" };

			var response = ReadWriteServiceTestModelSimple.Save(testModel);

			Assert.Equal(SaveResult.Saved, response);
		}

		[Fact]
		public void TheResponseFromTheMethodIsSaveResultValidationFailureWhenTheModelDoesNotPassValidation()
		{
			var testModel = new TestModelSimple();

			var response = ReadWriteServiceTestModelSimple.Save(testModel);

			Assert.Equal(SaveResult.ValidationFailure, response);
		}
	}

	public class WhenSaveWithCollectionIsCalled : ReadWriteServiceTests
	{
		[Fact]
		public void RepositorySaveMethodIsCalledOnceWithTheSameCollection()
		{
			var testModel1 = new TestModelSimple { TestField = "TestData" }; ;
			var testModel2 = new TestModelSimple { TestField = "TestData" }; ;
			var testModel3 = new TestModelSimple { TestField = "TestData" }; ;

			var testModelCollection = new List<TestModelSimple> {
				testModel1,
				testModel2,
				testModel3
			};

			ReadWriteServiceTestModelSimple.Save(testModelCollection);

			ReadWriteRepositoryMock.Verify(m => m.Save(It.Is<TestModelSimple>(model => model == testModel1)), Times.Once(), "The repository save method was not called for testModel1 or was called with the wrong model.");
			ReadWriteRepositoryMock.Verify(m => m.Save(It.Is<TestModelSimple>(model => model == testModel2)), Times.Once(), "The repository save method was not called for testModel2 or was called with the wrong model.");
			ReadWriteRepositoryMock.Verify(m => m.Save(It.Is<TestModelSimple>(model => model == testModel3)), Times.Once(), "The repository save method was not called for testModel3 or was called with the wrong model.");
		}

		[Fact]
		public void EachModelWillHaveASaveResultOfSaved()
		{
			var testModel1 = new TestModelSimple { TestField = "TestData" }; ;
			var testModel2 = new TestModelSimple { TestField = "TestData" }; ;
			var testModel3 = new TestModelSimple { TestField = "TestData" }; ;

			var testModelCollection = new List<TestModelSimple> {
				testModel1,
				testModel2,
				testModel3
			};

			var results = ReadWriteServiceTestModelSimple.Save(testModelCollection);

			Assert.Equal(SaveResult.Saved, results[testModel1]);
			Assert.Equal(SaveResult.Saved, results[testModel2]);
			Assert.Equal(SaveResult.Saved, results[testModel3]);
		}
	}

	public class WhenGetByIdIsCalled : ReadWriteServiceTests
	{
		[Fact]
		public void RepositoryDeleteByIdMethodIsCalledWithTheSameId()
		{
			var testId = ObjectId.GenerateNewId();

			ReadWriteServiceTestModelSimple.DeleteById(testId);

			ReadWriteRepositoryMock.Verify(m => m.DeleteById(testId), Times.Once());
		}
	}
}
